from leapp.actors import Actor
from leapp.libraries.actor.rpmscanner import get_package_repository_data
from leapp.libraries.common.rpms import get_installed_rpms
from leapp.models import InstalledRPM, RPM
from leapp.tags import IPUWorkflowTag, FactsPhaseTag

import os
from leapp.libraries import stdlib


class RpmScanner(Actor):
    """
    Provides data about installed RPM Packages.

    After collecting data from RPM query, a message with relevant data will be produced.
    """

    name = 'rpm_scanner'
    consumes = ()
    produces = (InstalledRPM,)
    tags = (IPUWorkflowTag, FactsPhaseTag)

    epel_package_name = "epel-release"

    def epel_but_not_in_source(self):
        epel_not_from_source = os.system("rpm -q %s" % self.epel_package_name)
        epel_exists = not os.system("yum repolist | grep -q '^epel'")

        return epel_not_from_source and epel_exists

    def process(self):
        output = get_installed_rpms()
        pkg_repos = get_package_repository_data()

        result = InstalledRPM()
        for entry in output:
            entry = entry.strip()
            if not entry:
                continue
            name, version, release, epoch, packager, arch, pgpsig = entry.split('|')
            repository = pkg_repos.get(name, '')
            result.items.append(RPM(
                name=name,
                version=version,
                epoch=epoch,
                packager=packager,
                arch=arch,
                release=release,
                pgpsig=pgpsig,
                repository=repository))

        import subprocess
        import re

        if self.epel_but_not_in_source():
            # disable epel repository
            subprocess.check_output("yum install -y yum-utils", shell=True)

            repos = str(subprocess.check_output("yum repolist | grep -v '^repolist: ' | grep -v '^repo id ' | grep -v '^ * ' |" \
                        "grep -v '^Loaded plugins: ' | grep -v '^Loading ' | awk '{ print $1 }' | xargs", shell=True)).strip()

            disable_repo_command = "yum-config-manager --disable "

            # repos = [ repo.split('/')[0] for repo in repos.split() ]
            for repo_raw in repos.split():
                repo = repo_raw.split('/')[0].replace('!', '').replace('*', '')
                if re.match(r"^epel", repo):
                    subprocess.check_output(disable_repo_command + repo, shell=True)

            # epel-release repository file backup
            repo_paths = str(subprocess.check_output("repoquery -l %s | egrep '\.repo$'" % self.epel_package_name, shell=True)).strip().split()
            for repo_path in repo_paths:
                if os.path.exists(repo_path):
                    os.rename(repo_path, repo_path + ".bak")

            # replace epel repo with yum source to ensure that epel stabe during migration
            subprocess.check_output("yum install -y %s" % self.epel_package_name, shell=True)

        rpm_cmd = [
            '/bin/rpm',
            '-q',
            self.epel_package_name,
            '--queryformat',
            r'%{NAME}|%{VERSION}|%{RELEASE}|%|EPOCH?{%{EPOCH}}:{(none)}||%|PACKAGER?{%{PACKAGER}}:{(none)}||%|'
            r'ARCH?{%{ARCH}}:{}||%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{(none)}|}|\n'
        ]
        try:
            entries = stdlib.run(rpm_cmd, split=True)['stdout']

            # append epel-release entry to RPMs
            for entry in entries:
                name, version, release, epoch, packager, arch, pgpsig = entry.split('|')
                result.items.append(RPM(
                    name=name,
                    version=version,
                    epoch=epoch,
                    packager=packager,
                    arch=arch,
                    release=release,
                    pgpsig=pgpsig,
                    repository='',
                ))

        except stdlib.CalledProcessError as err:
            error = 'Execution of {CMD} returned {RC}. Unable to find installed packages.'.format(CMD=err.command, RC=err.exit_code)
            stdlib.api.current_logger().error(error)
        self.produce(result)
